package com.thinkwide.data.servlet;

import com.thinkwide.data.core.MFPath;
import com.thinkwide.data.core.MFString;
import com.thinkwide.data.ormapping.MFDbTypeTransfer;
import com.thinkwide.data.ormapping.MFReflect;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class MFServletManager {
    private List<String> includeFiles;
    private Map<String, String> configs;
    private MFServletItems servletItems;
    private MFServletMappingItems servletMapItems;
    private HttpServletRequest request;
    private HttpServletResponse response;
    private ServletContext servletContext;

    public MFServletManager() {
        includeFiles = new ArrayList<String>();
        configs = new HashMap<String, String>();
        //loadMain();
        setServletItems(new MFServletItems());
        servletMapItems = new MFServletMappingItems();
    }


    public MFServletManager(HttpServletRequest request, HttpServletResponse response, ServletContext servletContext) {
        this();
        updateState(request, response, servletContext);
    }

    public void updateState(HttpServletRequest request, HttpServletResponse response, ServletContext servletContext) {
        this.request = request;
        this.response = response;
        this.servletContext = servletContext;
    }

    public boolean prepareProperty(Class<?> classType, Object obj) throws Throwable {

        Enumeration params = request.getParameterNames();
        while (params.hasMoreElements()) {
            String name = (String) params.nextElement();
            String value = request.getParameter(name);

            if (MFString.notNullOrEmpty(name) && MFReflect.isHaveProperty(obj, name)) {
                Class<?> type = MFReflect.getPropertyType(obj, name);
                Object typedValue = MFDbTypeTransfer.toJavaType(type, value);
                MFReflect.setProperty(obj, name, typedValue);

            }
        }
        return true;
    }

    public boolean runServlet(MFServletMappingItem item) throws Throwable {
        if (item != null) {
            MFServletItem servletItem = servletItems.find(item.getServletName());

            if (servletItem == null) throw new Exception("Not Found ServletName");

            Class<?> c = Class.forName(servletItem.getServletClass());

            Object obj = c.newInstance();
            HttpServlet servlet = (HttpServlet) obj;

            MFServletConfig config = new MFServletConfig();
            config.setServletName(item.getServletName());
            config.setServletContext(servletContext);

            config.setParamMap((HashMap) servletItem.getInitParam());
            servlet.init((ServletConfig) config);

            servlet.service(request, response);

        }
        return false;
    }

    public boolean hasServlet(String url) throws Throwable {
        MFServletMappingItem item = servletMapItems.findUrl(url);
        if (item != null) {
            MFServletItem servlet = servletItems.find(item.getServletName());
            return servlet != null;
        }
        return false;
    }

    public boolean runServlet(String url) throws Throwable {
        MFServletMappingItem item = servletMapItems.findUrl(url);
        return runServlet(item);
    }

    public String CheckPath(String url) {
        if (MFString.notNullOrEmpty(url) && !url.startsWith(MFPath.useparator)) {
            url = MFPath.useparator + url;
        }
        return url;
    }


    public String getAttrValue(Element item, String name) {
        Attribute attr = item.attribute(name);
        if (attr != null) {
            String text = attr.getText();
            return text;
        }
        return null;
    }

    public String getNodeValue(Element item, String name) {
        Element elem = item.element(name);
        if (elem != null) {
            String text = elem.getStringValue();
            return text;
        }
        return null;
    }

    public boolean loadConfig(String filePath) throws DocumentException {
        File file = new File(filePath);

        SAXReader reader = new SAXReader();
        Document doc = reader.read(file);
        Element root = doc.getRootElement();

        //load include file
        for (Iterator<?> i = root.elementIterator("include"); i.hasNext(); ) {
            Element item = (Element) i.next();
            String value = getAttrValue(item, "file");
            if (MFString.notNullOrEmpty(value)) {
                includeFiles.add(value);
            }
        }

        //load constant
        for (Iterator<?> i = root.elementIterator("constant"); i.hasNext(); ) {
            Element item = (Element) i.next();

            String conName = getAttrValue(item, "name");
            String conValue = getAttrValue(item, "value");
            if (MFString.notNullOrEmpty(conName) && MFString.notNullOrEmpty(conValue)) {
                configs.put(conName, conValue);
            }
        }

        //load Servlet
        for (Iterator<?> i = root.elementIterator("servlet"); i.hasNext(); ) {
            Element servletItem = (Element) i.next();
            String servletName = getNodeValue(servletItem, "servlet-name");
            String servletClass = getNodeValue(servletItem, "servlet-class");

            MFServletItem servlet = new MFServletItem();
            servlet.setServletClass(servletClass);
            servlet.setServletName(servletName);

            for (Iterator<?> j = servletItem.elementIterator("init-param"); j.hasNext(); ) {
                Element paramItem = (Element) j.next();

                String paramName = getNodeValue(paramItem, "param-name");
                String paramValue = getNodeValue(paramItem, "param-value");

                servlet.getInitParam().put(paramName, paramValue);

            }
            servletItems.add(servlet);
        }

        for (Iterator<?> i = root.elementIterator("servlet-mapping"); i.hasNext(); ) {
            MFServletMappingItem mappingItem = new MFServletMappingItem();

            Element servletItem = (Element) i.next();
            String servletName = getNodeValue(servletItem, "servlet-name");
            String urlPattern = getNodeValue(servletItem, "url-pattern");

            mappingItem.setUrlPattern(urlPattern);
            mappingItem.setServletName(servletName);

            servletMapItems.add(mappingItem);
        }

        return true;
    }

    public void setIncludeFiles(List<String> includeFiles) {
        this.includeFiles = includeFiles;
    }

    public List<String> getIncludeFiles() {
        return includeFiles;
    }


    public void setServletItems(MFServletItems servletItems) {
        this.servletItems = servletItems;
    }

    public MFServletItems getServletItems() {
        return servletItems;
    }
}
